//w25q_sample.c
#include <rtthread.h>
#include <rtdevice.h>
#include  <string.h> //add by chow
#include "board.h"
#include "drv_soft_spi.h"
//
#include <stdint.h>
#include <rtdevice.h>
#include "spi_flash.h"
#include "spi_flash_sfud.h"
#include <dfs_elm.h>
#include <dfs_fs.h>
#include <dfs_posix.h>
#include "drv_gpio.h"

#define DBG_LVL DBG_LOG
#define DBG_TAG "spi.W25Q256"
#include <rtdbg.h>

#define SPI_FLASH_BLOCK     "W25Q256"
#define SPI_FLASH_DEVICE    "spi0w" //设备名字不能重名,要短
#define SPI_BUS_NAME        "spi0"
#define SPI_FLASH_CS        "PA.5"

#define SPI_FLASH_DEVICE_TEST    "spi0T" //设备名字不能重名,要短

static struct rt_spi_device *spi_dev_w25q;
rt_uint8_t w25x_device_id[4] = { 0x90, 0x00, 0x00, 0x00 };
rt_uint8_t id[5] = { 0 };
static void w25q_erase(void)
{
    rt_uint8_t chip_erase[1] = { 0x20 };
    struct rt_spi_message msg;
    msg.send_buf = chip_erase;
    msg.recv_buf = RT_NULL;
    msg.length = 1;
    msg.next = RT_NULL;
    msg.cs_take = 0;
    msg.cs_release = 1;
    rt_spi_transfer_message(spi_dev_w25q, &msg);
    rt_kprintf("erase success\r\n");
}
void w25q_sector_erase(rt_uint32_t SectorAddr)
{
    rt_uint8_t page_write_cmd[4];
    rt_uint8_t write_enable = 0x06;
    struct rt_spi_message msg3;
    msg3.send_buf = &write_enable;
    msg3.recv_buf = RT_NULL;
    msg3.length = 1;
    msg3.next = RT_NULL;
    msg3.cs_take = 1;
    msg3.cs_release = 1;
    rt_spi_transfer_message(spi_dev_w25q, &msg3);
    page_write_cmd[0] = 0x20;
    page_write_cmd[1] = (SectorAddr & 0xFF0000) >> 16;
    page_write_cmd[2] = (SectorAddr & 0xFF00) >> 8;
    page_write_cmd[3] = SectorAddr & 0xFF;
    struct rt_spi_message msg, msg2;
    msg.send_buf = page_write_cmd;
    msg.recv_buf = RT_NULL;
    msg.length = 4;
    msg.next = RT_NULL;
    msg.cs_take = 1;
    msg.cs_release = 1;
    rt_spi_transfer_message(spi_dev_w25q, &msg);
}
void w25q_page_write(rt_uint8_t* pBuffer, rt_uint32_t WriteAddr, rt_uint16_t NumByteToWrite)
{
    rt_uint8_t page_write_cmd[4];
    rt_uint8_t write_enable = 0x06;
    struct rt_spi_message msg3;
    msg3.send_buf = &write_enable;
    msg3.recv_buf = RT_NULL;
    msg3.length = 1;
    msg3.next = RT_NULL;
    msg3.cs_take = 1;
    msg3.cs_release = 1;
    rt_spi_transfer_message(spi_dev_w25q, &msg3);
    page_write_cmd[0] = 0x02;
    page_write_cmd[1] = (WriteAddr & 0xFF0000) >> 16;
    page_write_cmd[2] = (WriteAddr & 0xFF00) >> 8;
    page_write_cmd[3] = WriteAddr & 0xFF;
    struct rt_spi_message msg, msg2;
    msg.send_buf = page_write_cmd;
    msg.recv_buf = RT_NULL;
    msg.length = 4;
    msg.next = RT_NULL;
    msg.cs_take = 1;
    msg.cs_release = 0;
    rt_spi_transfer_message(spi_dev_w25q, &msg);
    msg2.send_buf = pBuffer;
    msg2.recv_buf = RT_NULL;
    msg2.length = NumByteToWrite;
    msg2.next = RT_NULL;
    msg2.cs_take = 0;
    msg2.cs_release = 1;
    rt_spi_transfer_message(spi_dev_w25q, &msg2);
    rt_kprintf("write done\r\n");
}
void w25q_buffer_read(rt_uint8_t* pBuffer, rt_uint32_t ReadAddr, rt_uint16_t NumByteToRead)
{
    rt_uint8_t buffer_read_cmd[4];
    rt_uint8_t write_enable = 0x06;
    struct rt_spi_message msg3;
    msg3.send_buf = &write_enable;
    msg3.recv_buf = RT_NULL;
    msg3.length = 1;
    msg3.next = RT_NULL;
    msg3.cs_take = 1;
    msg3.cs_release = 1;
    rt_spi_transfer_message(spi_dev_w25q, &msg3);
    buffer_read_cmd[0] = 0x03;
    buffer_read_cmd[1] = (ReadAddr & 0xFF0000) >> 16;
    buffer_read_cmd[2] = (ReadAddr & 0xFF00) >> 8;
    buffer_read_cmd[3] = ReadAddr & 0xFF;
    struct rt_spi_message msg, msg2;
    msg.send_buf = buffer_read_cmd;
    msg.recv_buf = RT_NULL;
    msg.length = 4;
    msg.next = RT_NULL;
    msg.cs_take = 1;
    msg.cs_release = 0;
    rt_spi_transfer_message(spi_dev_w25q, &msg);
    msg2.send_buf = RT_NULL;
    msg2.recv_buf = pBuffer;
    msg2.length = NumByteToRead;
    msg2.next = RT_NULL;
    msg2.cs_take = 0;
    msg2.cs_release = 1;
    rt_spi_transfer_message(spi_dev_w25q, &msg2);
}
static void spi_w25q_sample(int argc, char *argv[])
{
    rt_uint8_t write_buf[100] = { 0 }; //{0x5a,0x5a,0x5a,0x5a,0x5a};
    memset(write_buf, 0xa5, 100);
    rt_uint8_t read_buf[100] = { 0 };
//
    rt_base_t pin_cs = rt_pin_get(SPI_FLASH_CS);
    rt_soft_spi_device_attach(SPI_BUS_NAME, SPI_FLASH_DEVICE_TEST, RT_NULL, pin_cs);

//
//查找 spi 设备获取地址
    spi_dev_w25q = (struct rt_spi_device *) rt_device_find(SPI_FLASH_DEVICE);
    if (!spi_dev_w25q)
    {
        rt_kprintf("spi sample run failed\n");
    }
    else
    {
        struct rt_spi_configuration cfg;
        cfg.data_width = 8;
        cfg.mode = RT_SPI_MASTER | RT_SPI_MSB | RT_SPI_MODE_0;
        cfg.max_hz = 1 * 1000; //1.92 M
        rt_spi_configure(spi_dev_w25q, &cfg);
        struct rt_spi_message msg1, msg2;
        w25x_device_id[0] = 0x90;
        w25x_device_id[1] = 0x00;
        w25x_device_id[2] = 0x00;
        w25x_device_id[3] = 0x00;
        msg1.send_buf = w25x_device_id;
        msg1.recv_buf = RT_NULL;
        msg1.length = 4;
        msg1.cs_take = 1;
        msg1.cs_release = 0;
        msg1.next = &msg2;
        msg2.send_buf = RT_NULL;
        msg2.recv_buf = id;
        msg2.length = 5;
        msg2.cs_take = 0;
        msg2.cs_release = 1;
        msg2.next = RT_NULL;
        rt_spi_transfer_message(spi_dev_w25q, &msg1);
        rt_kprintf("use rt_spi_transfer_message() read w25q ID is:%02x %02x %02x %02x %02x\n", id[0], id[1], id[2],
                id[3], id[4]);
        rt_thread_mdelay(1000);
        w25q_sector_erase(0);
        rt_thread_mdelay(6000);
        w25q_page_write(write_buf, 0, 100);
        rt_thread_mdelay(1000);
        rt_kprintf("write done \r\n");
        w25q_buffer_read(read_buf, 0, 100);
        rt_thread_mdelay(1000);
        for (rt_uint8_t i = 0; i < 100; i++)
        {
            rt_kprintf("%x ", read_buf[i]);
        }
    }
}

MSH_CMD_EXPORT(spi_w25q_sample, spi w25q sample);
//系统初始化才执行
//INIT_BOARD_EXPORT(spi01Init);
//INIT_APP_EXPORT(spi01Init);

int spi01Init(void)
{
    rt_spi_flash_device_t rtt_dev;
    rt_err_t err;
    rt_base_t pin_cs = rt_pin_get(SPI_FLASH_CS);
    //pin_cs=8;//default
    err = rt_soft_spi_device_attach(SPI_BUS_NAME, SPI_FLASH_DEVICE, RT_NULL, pin_cs); //8
    if (err != RT_EOK)
    {
        rt_kprintf( SPI_FLASH_DEVICE " rt_soft_spi_device_attach Failed from : " SPI_BUS_NAME "\r\n");
        return RT_ERROR;
    }rt_kprintf( SPI_FLASH_DEVICE " device created from spi bus :" SPI_BUS_NAME "\r\n");

    //rtt_dev = rt_sfud_flash_probe("sf_cmd", spi_dev_name);
    // rtt_dev = rt_sfud_flash_probe(SPI_FLASH_BLOCK, SPI_FLASH_DEVICE);
    if (!rtt_dev)
    {
        rt_kprintf( SPI_FLASH_DEVICE " rt_sfud_flash_probe FAILED \r\n");
        return RT_ERROR;
    }
    return RT_EOK;
}
MSH_CMD_EXPORT(spi01Init, spi bus:spi0 device spi0.1);
//初始化即生成设备节点
//INIT_BOARD_EXPORT(spi01Init);

//探测flash并挂载到/
int spi_flash_mount(void)
{
    rt_spi_flash_device_t rtt_dev;
    rt_err_t err;
    rt_base_t pin_cs = rt_pin_get(SPI_FLASH_CS);
    //pin_cs=8;//default
    err = rt_soft_spi_device_attach(SPI_BUS_NAME, SPI_FLASH_DEVICE, RT_NULL, pin_cs); //8
    if (err != RT_EOK)
    {
        rt_kprintf( SPI_FLASH_DEVICE " rt_soft_spi_device_attach Failed from : " SPI_BUS_NAME "\r\n");
        return RT_ERROR;
    }rt_kprintf( SPI_FLASH_DEVICE " device created from spi bus :" SPI_BUS_NAME "\r\n");

    //rtt_dev = rt_sfud_flash_probe("sf_cmd", spi_dev_name);
    rtt_dev = rt_sfud_flash_probe(SPI_FLASH_BLOCK, SPI_FLASH_DEVICE);
    if (!rtt_dev)
    {
        rt_kprintf( SPI_FLASH_BLOCK " rt_sfud_flash_probe FAILED \r\n");
        return RT_ERROR;
    }rt_kprintf( SPI_FLASH_BLOCK " rt_sfud_flash_probe OK \r\n");

    //开始挂载
    if (rt_device_find(SPI_FLASH_BLOCK) != RT_NULL)
    {
        if (dfs_mount(SPI_FLASH_BLOCK, "/", "elm", 0, 0) == RT_EOK)
        {
            LOG_I(SPI_FLASH_BLOCK " mount to '/' OK");
            return RT_ERROR;
        }
        else
        {
            LOG_W(SPI_FLASH_BLOCK "  mount to '/' failed!");
            //
            //
            ///////////////////////////////////////////////////////////////////////////
            //
            //
            if (dfs_mount(SPI_FLASH_BLOCK, "/spiflash", "elm", 0, 0) == RT_EOK)
            {
                LOG_I(SPI_FLASH_BLOCK " mount to '/spiflash' OK");
                return RT_ERROR;
            }
            else
            {
                LOG_W(SPI_FLASH_BLOCK "  mount to '/spiflash' failed!");
            }
        }
    }

    return RT_EOK;
}

//app初始化才执行
INIT_APP_EXPORT(spi_flash_mount);
MSH_CMD_EXPORT(spi_flash_mount, mount spi flash as fat);

